home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
- **
- ** This file is part of TACK.
- **
- ** TACK is free software; you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation; either version 2, or (at your option)
- ** any later version.
- **
- ** TACK is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with TACK; see the file COPYING. If not, write to
- ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- ** Boston, MA 02111-1307, USA.
- */
- /*
- * Operating system dependent functions. We assume the POSIX API.
- * Note: on strict-POSIX systems (including BSD/OS) the select_delay_type
- * global has no effect.
- */
-
- #include <signal.h> /* include before curses.h to work around glibc bug */
-
- #include <tack.h>
-
- #include <term.h>
- #include <errno.h>
-
- #if defined(__BEOS__)
- #undef false
- #undef true
- #include <OS.h>
- #endif
-
- #if HAVE_SELECT
- #if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT
- #include <sys/time.h>
- #endif
- #if HAVE_SYS_SELECT_H
- #include <sys/select.h>
- #endif
- #endif
-
- MODULE_ID("$Id: sysdep.c,v 1.11 2002/04/21 19:40:43 tom Exp $")
-
- #if DECL_ERRNO
- extern int errno;
- #endif
-
- #ifdef TERMIOS
- #define PUT_TTY(fd, buf) tcsetattr(fd, TCSAFLUSH, buf)
- #else
- #define PUT_TTY(fd, buf) stty(fd, buf)
- #endif
-
- /* globals */
- int tty_frame_size; /* asynch frame size times 2 */
- unsigned long tty_baud_rate; /* baud rate - bits per second */
- int not_a_tty; /* TRUE if output is not a tty (i.e. pipe) */
- int nodelay_read; /* TRUE if NDELAY is set */
-
- #ifdef TERMIOS
- #define TTY_IS_NOECHO !(new_modes.c_lflag & ECHO)
- #define TTY_IS_OUT_TRANS (new_modes.c_oflag & OPOST)
- #define TTY_IS_CHAR_MODE !(new_modes.c_lflag & ICANON)
- #define TTY_WAS_CS8 ((old_modes.c_cflag & CSIZE) == CS8)
- #define TTY_WAS_XON_XOFF (old_modes.c_iflag & (IXON|IXOFF))
- #else
- #define TTY_IS_NOECHO !(new_modes.sg_flags & (ECHO))
- #define TTY_IS_OUT_TRANS (new_modes.sg_flags & (CRMOD))
- #define TTY_IS_CHAR_MODE (new_modes.sg_flags & (RAW|CBREAK))
- #define TTY_WAS_CS8 (old_modes.sg_flags & (PASS8))
- #define TTY_WAS_XON_XOFF (old_modes.sg_flags & (TANDEM|MDMBUF|DECCTQ))
- #endif
-
- static TTY old_modes, new_modes;
-
- void catchsig(void);
-
- /*
- * These are a sneaky way of conditionalizing bit unsets so strict-POSIX
- * systems won't see them.
- */
- #ifndef XCASE
- #define XCASE 0
- #endif
- #ifndef OLCUC
- #define OLCUC 0
- #endif
- #ifndef IUCLC
- #define IUCLC 0
- #endif
- #ifndef TABDLY
- #define TABDLY 0
- #endif
- #ifndef IXANY
- #define IXANY 0
- #endif
-
- void
- tty_raw(int minch GCC_UNUSED, int mask)
- { /* set tty to raw noecho */
- new_modes = old_modes;
- #ifdef TERMIOS
- #if HAVE_SELECT
- new_modes.c_cc[VMIN] = 1;
- #else
- new_modes.c_cc[VMIN] = minch;
- #endif
- new_modes.c_cc[VTIME] = 2;
- new_modes.c_lflag &=
- ~(ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK | ECHONL);
- #ifdef LOBLK
- new_modes.c_lflag &= ~LOBLK;
- #endif
- new_modes.c_oflag &= ~(OPOST | OLCUC | TABDLY);
- if (mask == ALLOW_PARITY) {
- new_modes.c_cflag &= ~(CSIZE | PARENB | HUPCL);
- new_modes.c_cflag |= CS8;
- }
- new_modes.c_iflag &=
- ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL |
- IUCLC | IXON | IXANY | IXOFF);
- #else
- new_modes.sg_flags |= RAW;
- #endif
- if (not_a_tty)
- return;
- PUT_TTY(fileno(stdin), &new_modes);
- }
-
- void
- tty_set(void)
- { /* set tty to special modes */
- new_modes = old_modes;
- #ifdef TERMIOS
- new_modes.c_cc[VMIN] = 1;
- new_modes.c_cc[VTIME] = 1;
- new_modes.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
- #if defined(ONLCR) && defined(OCRNL) && defined(ONLRET) && defined(OFILL)
- new_modes.c_oflag &= ~(ONLCR | OCRNL | ONLRET | OFILL);
- #else
- new_modes.c_oflag &= ~(OPOST);
- #endif
- if (char_mask == ALLOW_PARITY)
- new_modes.c_iflag &= ~ISTRIP;
- switch (select_xon_xoff) {
- case 0:
- new_modes.c_iflag &= ~(IXON | IXOFF);
- break;
- case 1:
- #if defined(sequent) && sequent
- /* the sequent System V emulation is broken */
- new_modes = old_modes;
- new_modes.c_cc[VEOL] = 6; /* control F (ACK) */
- #endif
- new_modes.c_iflag |= IXON | IXOFF;
- break;
- }
- switch (select_delay_type) {
- case 0:
- #ifdef NLDLY
- new_modes.c_oflag &=
- ~(NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
- #endif /* NLDLY */
- break;
- case 1:
- #ifdef NLDLY
- new_modes.c_oflag &=
- ~(NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
- #endif /* NLDLY */
- #ifdef NL1
- new_modes.c_oflag |= NL1 | CR2;
- #endif /* NL1 */
- break;
- }
- if (!(new_modes.c_oflag & ~OPOST))
- new_modes.c_oflag &= ~OPOST;
- #else
- new_modes.sg_flags |= RAW;
- if (not_a_tty)
- return;
- #endif
- PUT_TTY(fileno(stdin), &new_modes);
- }
-
-
- void
- tty_reset(void)
- { /* reset the tty to the original modes */
- fflush(stdout);
- if (not_a_tty)
- return;
- PUT_TTY(fileno(stdin), &old_modes);
- }
-
-
- void
- tty_init(void)
- { /* ATT terminal init */
- #if defined(F_GETFL) && defined(O_NDELAY)
- int flags;
-
- flags = fcntl(fileno(stdin), F_GETFL, 0);
- nodelay_read = flags & O_NDELAY;
- #else
- nodelay_read = FALSE;
- #endif
- not_a_tty = FALSE;
- if (GET_TTY(fileno(stdin), &old_modes) == -1) {
- if (errno == ENOTTY) {
- tty_frame_size = 20;
- not_a_tty = TRUE;
- return;
- }
- printf("tcgetattr error: %d\n", errno);
- exit(1);
- }
- /* if TAB3 is set then setterm() wipes out tabs (ht) */
- new_modes = old_modes;
- #ifdef TERMIOS
- #ifdef TABDLY
- new_modes.c_oflag &= ~TABDLY;
- #endif /* TABDLY */
- #endif
- if (PUT_TTY(fileno(stdin), &new_modes) == -1) {
- printf("tcsetattr error: %d\n", errno);
- exit(1);
- }
- #ifdef sequent
- /* the sequent ATT emulation is broken soooo. */
- old_modes.c_cflag &= ~(CSIZE | CSTOPB);
- old_modes.c_cflag |= CS7 | PARENB;
- #endif
- catchsig();
- #ifdef TERMIOS
- switch (old_modes.c_cflag & CSIZE) {
- #if defined(CS5) && (CS5 != 0)
- case CS5:
- tty_frame_size = 10;
- break;
- #endif
- #if defined(CS6) && (CS6 != 0)
- case CS6:
- tty_frame_size = 12;
- break;
- #endif
- #if defined(CS7) && (CS7 != 0)
- case CS7:
- tty_frame_size = 14;
- break;
- #endif
- #if defined(CS8) && (CS8 != 0)
- case CS8:
- tty_frame_size = 16;
- break;
- #endif
- }
- tty_frame_size += 2 +
- ((old_modes.c_cflag & PARENB) ? 2 : 0) +
- ((old_modes.c_cflag & CSTOPB) ? 4 : 2);
- #else
- tty_frame_size = 6 +
- (old_modes.sg_flags & PASS8) ? 16 : 14;
- #endif
- }
-
- /*
- ** stty_query(question)
- **
- ** Does the current driver settings have this property?
- */
- int
- stty_query(int q)
- {
- switch (q) {
- case TTY_NOECHO:
- return TTY_IS_NOECHO;
- case TTY_OUT_TRANS:
- return TTY_IS_OUT_TRANS;
- case TTY_CHAR_MODE:
- return TTY_IS_CHAR_MODE;
- }
- return (-1);
- }
-
- /*
- ** initial_stty_query(question)
- **
- ** Did the initial driver settings have this property?
- */
- int
- initial_stty_query(int q)
- {
- switch (q) {
- case TTY_8_BIT:
- return TTY_WAS_CS8;
- case TTY_XON_XOFF:
- return TTY_WAS_XON_XOFF;
- }
- return (-1);
- }
-
- #if HAVE_SELECT && defined(FD_ZERO)
- static int
- char_ready(void)
- {
- int n;
- fd_set ifds;
- struct timeval tv;
-
- FD_ZERO(&ifds);
- FD_SET(fileno(stdin), &ifds);
- tv.tv_sec = 0;
- tv.tv_usec = 200000;
- n = select(fileno(stdin)+1, &ifds, NULL, NULL, &tv);
- return (n != 0);
- }
-
- #else
- #ifdef FIONREAD
- int
- char_ready(void)
- {
- int i, j;
-
- /* the following loop has to be tuned for each computer */
- for (j = 0; j < 1000; j++) {
- ioctl(fileno(stdin), FIONREAD, &i);
- if (i)
- return i;
- }
- return i;
- }
-
- #else
- #if defined(__BEOS__)
- int
- char_ready(void)
- {
- int n = 0;
- int howmany = ioctl(0, 'ichr', &n);
- return (howmany >= 0 && n > 0);
- }
- #else
- #define char_ready() 1
- #endif
- #endif
- #endif
-
- /*
- ** spin_flush()
- **
- ** Wait for the input stream to stop.
- ** Throw away all input characters.
- */
- void
- spin_flush(void)
- {
- unsigned char buf[64];
-
- fflush(stdout);
- event_start(TIME_FLUSH); /* start the timer */
- do {
- if (char_ready()) {
- (void) read(fileno(stdin), &buf, sizeof(buf));
- }
- } while (event_time(TIME_FLUSH) < 400000);
- }
-
- /*
- ** read_key(input-buffer, length-of-buffer)
- **
- ** read one function key from the input stream.
- ** A null character is converted to 0x80.
- */
- void
- read_key(char *buf, int max)
- {
- int got, ask, i, l;
- char *s;
-
- *buf = '\0';
- s = buf;
- fflush(stdout);
- /* ATT unix may return 0 or 1, Berkeley Unix should be 1 */
- while (read(fileno(stdin), s, 1) == 0);
- ++s;
- --max;
- while (max > 0 && (ask = char_ready())) {
- if (ask > max) {
- ask = max;
- }
- if ((got = read(fileno(stdin), s, ask))) {
- s += got;
- } else {
- break;
- }
- max -= got;
- }
- *s = '\0';
- l = s - buf;
- for (s = buf, i = 0; i < l; i++) {
- if ((*s & 0x7f) == 0) {
- /* convert nulls to 0x80 */
- *(unsigned char *)s = 128;
- } else {
- /* strip high order bits (if any) */
- *s &= char_mask;
- }
- }
- }
-
-
- void
- ignoresig(void)
- {
- /* ignore signals */
- signal(SIGINT, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- signal(SIGTERM, SIG_IGN);
- signal(SIGALRM, SIG_IGN);
- }
-
- /*
- onintr( )
-
- is the interrupt handling routine onintr turns off interrupts while doing
- clean-up
-
- onintr always exits fatally
- */
-
-
- static RETSIGTYPE
- onintr(int sig GCC_UNUSED)
- {
- ignoresig();
- tty_reset();
- exit(1);
- }
-
-
- /*
- catchsig( )
-
- set up to field interrupts (via function onintr( )) so that if interrupted
- we can restore the correct terminal modes
-
- catchsig simply returns
- */
-
-
- void
- catchsig(void)
- {
- if ((signal(SIGINT, SIG_IGN)) == SIG_DFL)
- signal(SIGINT, onintr);
-
- if ((signal(SIGHUP, SIG_IGN)) == SIG_DFL)
- signal(SIGHUP, onintr);
-
- if ((signal(SIGQUIT, SIG_IGN)) == SIG_DFL)
- signal(SIGQUIT, onintr);
-
- if ((signal(SIGTERM, SIG_IGN)) == SIG_DFL)
- signal(SIGTERM, onintr);
-
- }
-
- /*
- ** alarm_event(sig)
- **
- ** Come here for an alarm event
- */
- static void
- alarm_event(
- int sig GCC_UNUSED)
- {
- no_alarm_event = 0;
- }
-
- /*
- ** set_alarm_clock(seconds)
- **
- ** Set the alarm clock to fire in <seconds>
- */
- void
- set_alarm_clock(
- int seconds)
- {
- signal(SIGALRM, alarm_event);
- no_alarm_event = 1;
- (void) alarm(seconds);
- }
-